package com.atuguigu.gmall.cart.service;

import com.alibaba.fastjson.JSON;
import com.atguigu.gmall.common.bean.ResponseVo;
import com.atguigu.gmall.common.exception.CartException;
import com.atguigu.gmall.pms.entity.SkuAttrValueEntity;
import com.atguigu.gmall.pms.entity.SkuEntity;
import com.atguigu.gmall.sms.vo.ItemSaleVo;
import com.atguigu.gmall.wms.entity.WareSkuEntity;
import com.atuguigu.gmall.cart.feign.GmallPmsClient;
import com.atuguigu.gmall.cart.feign.GmallSmsClient;
import com.atuguigu.gmall.cart.feign.GmallWmsClient;
import com.atuguigu.gmall.cart.interceptor.LoginInterceptor;
import com.atuguigu.gmall.cart.mapper.CartMapper;
import com.atuguigu.gmall.cart.pojo.Cart;
import com.atuguigu.gmall.cart.pojo.UserInfo;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.concurrent.ListenableFuture;

import java.math.BigDecimal;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class CartService {

    private static final String KEY_PREFIX = "cart:info:";

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private CartAsyncService asyncService;

    @Autowired
    private GmallPmsClient pmsClient;

    @Autowired
    private GmallSmsClient smsClient;

    @Autowired
    private GmallWmsClient wmsClient;

    public void addCart(Cart cart) {
        //获取登录状态
        String userId = getUserId();

        //外层的key
        String key = KEY_PREFIX + userId;
        //当前用户的购物车：获取了内层的map<skuId,cartJson>
        BoundHashOperations<String, Object, Object> hashOps = this.redisTemplate.boundHashOps(key);
        //判断当前用户的购物车，是否包含该商品
        String skuId = cart.getSkuId().toString();
        BigDecimal count = cart.getCount();//新增购物车时的数量
        if (hashOps.hasKey(skuId)) {
            //更新数量
            String cartJson = hashOps.get(skuId).toString();
            cart = JSON.parseObject(cartJson, Cart.class);
            cart.setCount(cart.getCount().add(count)); //获取数据库里面的Count
            // 更新到mysql数据库
            this.asyncService.update(userId, cart.getSkuId(), cart);
        } else {
            //新增一条记录: skuId  count
            cart.setUserId(userId);
            cart.setCheck(true);

            //sku
            ResponseVo<SkuEntity> skuEntityResponseVo = this.pmsClient.querySkuById(cart.getSkuId());
            SkuEntity skuEntity = skuEntityResponseVo.getData();
            if (skuEntity == null) {
                throw new CartException("您添加的商品不存在！");
            }
            cart.setDefaultImage(skuEntity.getDefaultImage());
            cart.setPrice(skuEntity.getPrice());
            cart.setTitle(skuEntity.getTitle());

            //销售属性
            ResponseVo<List<SkuAttrValueEntity>> saleAttrsResponseVo = this.pmsClient.querySaleAttrsBySkuId(cart.getSkuId());
            List<SkuAttrValueEntity> skuAttrValueEntities = saleAttrsResponseVo.getData();
            cart.setSaleAttrs(JSON.toJSONString(skuAttrValueEntities));

            //库存信息
            ResponseVo<List<WareSkuEntity>> wareResponseVo = this.wmsClient.queryWareSkusBySkuId(cart.getSkuId());
            List<WareSkuEntity> wareSkuEntities = wareResponseVo.getData();
            if (!CollectionUtils.isEmpty(wareSkuEntities)) {
                cart.setStore(wareSkuEntities.stream().anyMatch(wareSkuEntity -> wareSkuEntity.getStock() - wareSkuEntity.getStockLocked() > 0));
            }

            //营销信息
            ResponseVo<List<ItemSaleVo>> responseVo = this.smsClient.querySalesBySkuId(cart.getSkuId());
            List<ItemSaleVo> itemSaleVos = responseVo.getData();
            cart.setSales(JSON.toJSONString(itemSaleVos));
            //保存到MySQL数据库
            this.asyncService.insert(cart);
        }
        //新增到Redis
        hashOps.put(skuId, JSON.toJSONString(cart));
    }

    private String getUserId() {
        UserInfo userInfo = LoginInterceptor.getUserInfo();
        String userId = userInfo.getUserKey();  //定义一个 userId，如果userId为空则key就是userKey，如果userId不为空，则key就是userId
        if (userInfo.getUserId() != null) {
            userId = userInfo.getUserId().toString();
        }
        return userId;
    }

    public Cart queryCart(Long skuId) {
        //获取用户的登录状态
        String userId = this.getUserId();

        //组装外层key
        String key = KEY_PREFIX + userId;
        //获取内层的map
        BoundHashOperations<String, Object, Object> hashOps = this.redisTemplate.boundHashOps(key);
        if (!hashOps.hasKey(skuId.toString())) {
            throw new CartException("该用户不包含当前商品的购物车记录");
        }
        String json = hashOps.get(skuId.toString()).toString();
        return JSON.parseObject(json, Cart.class);
    }

    @Async
    public void execute1() {
        try {
            System.out.println("3 execute1方法开始执行---------------------");
            TimeUnit.SECONDS.sleep(5);
            int i = 1 / 0;
            System.out.println("execute1方法结束执行=====================");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Async
    public void execute2() {
        try {
            System.out.println("4 execute2方法开始执行---------------------");
            TimeUnit.SECONDS.sleep(4);
            System.out.println("5 execute2方法结束执行=====================");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public List<Cart> queryCarts() {
        //1、获取userKey
        UserInfo userInfo = LoginInterceptor.getUserInfo();
        String userKey = userInfo.getUserKey();

        //2、以userKey作为key，查询未登录地购物车   Map<skuId,cartJson>
        BoundHashOperations<String, Object, Object> unloginHashOps = this.redisTemplate.boundHashOps(userKey);
        List<Object> cartJsons = unloginHashOps.values();
        List<Cart> unloginCarts = null;
        if (CollectionUtils.isEmpty(cartJsons)) {
            unloginCarts = cartJsons.stream().map(cartJson -> JSON.parseObject(cartJson.toString(), Cart.class)).collect(Collectors.toList());
        }

        //3、获取userId，如果为空，则直接返回未登录的购物车
        Long userId = userInfo.getUserId();
        if (userId == null) {
            return unloginCarts;    //如果userId为空，则直接返回未登录购物车的数据
        }

        //4、合并未登录的购物车，到已登录的购物车中
        BoundHashOperations<String, Object, Object> loginHashOps = this.redisTemplate.boundHashOps(KEY_PREFIX + userId);
        if (!CollectionUtils.isEmpty(unloginCarts)) {
            unloginCarts.forEach(cart -> {
                String skuId = cart.getSkuId().toString();
                BigDecimal count = cart.getCount();  //未登录购物车数量
                if (loginHashOps.hasKey(skuId)) {
                    //更新数量
                    String json = loginHashOps.get(skuId).toString();//获取对应的已登录购物车对象的json字符串
                    cart = JSON.parseObject(json, Cart.class);
                    cart.setCount(cart.getCount().add(count));
                    //更新到redis、数据库
                    this.asyncService.update(userId.toString(), cart.getSkuId(), cart);
                } else {
                    //新增一条记录
                    cart.setUserId(userId.toString());
                    this.asyncService.insert(cart);
                }
                loginHashOps.put(skuId, JSON.toJSONString(cart));
            });
        }

        //5、删除未登录的购物车
        this.redisTemplate.delete(KEY_PREFIX + userKey);
        this.asyncService.deleteByUserId(userKey);

        //6、查询已登录的购物车
        List<Object> loginCartJsons = loginHashOps.values();
        if (CollectionUtils.isEmpty(loginCartJsons)){
            return null;
        }

        return loginCartJsons.stream().map(cartJson -> JSON.parseObject(cartJson.toString(), Cart.class)).collect(Collectors.toList());
    }
}
